package org.pp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.pp.admin.dto.*;
import org.pp.core.*;
import org.pp.entity.PpGoods;
import org.pp.entity.PpGoodsAttr;
import org.pp.entity.PpGoodsCategorize;
import org.pp.entity.PpGoodsSku;
import org.pp.mapper.PpGoodsMapper;
import org.pp.miniapp.dto.GoodsSearch;
import org.pp.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.pp.store.OssStore;
import org.pp.util.PageUtil;
import org.pp.vo.AdminMiniappGoodsDetailVo;
import org.pp.vo.AdminGoodsVo;
import org.pp.vo.MiniappGoodsVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * <p>
 * 商品 服务实现类
 * </p>
 *
 * @author haima
 * @since 2024-06-02
 */
@Service
public class PpGoodsServiceImpl extends ServiceImpl<PpGoodsMapper, PpGoods> implements IPpGoodsService {

    @Autowired
    IPpGoodsAttrService attrService;

    @Autowired
    IPpGoodsSkuService skuService;

    @Autowired
    OssStore ossStore;

    @Autowired
    IPpGoodsCategorizeService goodsCategorizeService;

    @Autowired
    IPpPublicConfigService configService;

    @Override
    public PageBean<AdminGoodsVo> getPageList(PpGoodsPage page) {

        PageHelper.startPage(page.getPageNum(), page.getPageSize());
        List<AdminGoodsVo> pageList = baseMapper.getPageList(page);
        PageBean<AdminGoodsVo> res = PageUtil.load(new PageInfo<>(pageList), AdminGoodsVo.class);
        for (AdminGoodsVo adminPpGoodsVo : res.getList()) {
            adminPpGoodsVo.setCover(ossStore.getUrl(adminPpGoodsVo.getCover()));
        }
        return res;
    }

    @Override
    public void postageUpdate(PpGoodsPostageEdite dto) {
        PpGoods byId = getById(dto.getGoodsId());
        Assertion.nullThrow(byId, "商品不存在");
        PpGoods ppGoods = BeanUtil.copyProperties(dto, PpGoods.class);
        updateById(ppGoods);
    }

    @Override
    public void detailIntroUpdate(PpGoodsDetailIntroEdite dto) {
        PpGoods byId = getById(dto.getGoodsId());
        Assertion.nullThrow(byId, "商品不存在");
        PpGoods ppGoods = BeanUtil.copyProperties(dto, PpGoods.class);
        updateById(ppGoods);
    }

    @Override
    @Transactional
    public void attrUpdate(PpGoodsAttrEdite dto) {
        PpGoods byId = getById(dto.getGoodsId());
        Assertion.nullThrow(byId, "商品不存在");
        Assertion.emptyThrow(dto.getAttrs(), "属性不为空");
        //需要添加的
        List<PpGoodsAttrEdite.Attr> addAttr = dto.getAttrs().stream().filter(e -> e.getAttrId() == null).toList();
        List<PpGoodsAttr> addAttrs = BeanUtil.copyToList(addAttr, PpGoodsAttr.class);
        addAttrs.forEach(e -> e.setGoodsId(dto.getGoodsId()));


        //需要更新的
        List<PpGoodsAttrEdite.Attr> updateAttr = dto.getAttrs().stream().filter(e -> e.getAttrId() != null).toList();
        List<PpGoodsAttr> updateAttrs = BeanUtil.copyToList(updateAttr, PpGoodsAttr.class);
        updateAttrs.forEach(e -> e.setGoodsId(dto.getGoodsId()));


        //现在还存在的
        Set<Long> remaindIds = updateAttrs.stream().map(PpGoodsAttr::getAttrId).collect(Collectors.toSet());
        //需要删除的
        //123 ,23
        attrService.remove(new LambdaQueryWrapper<PpGoodsAttr>()
                .eq(PpGoodsAttr::getGoodsId, dto.getGoodsId())
                .notIn(!CollectionUtil.isEmpty(remaindIds), PpGoodsAttr::getAttrId, remaindIds)
        );
        attrService.saveBatch(addAttrs);
        attrService.updateBatchById(updateAttrs);
    }

    @Override
    @Transactional
    public void skuUpdate(PpGoodsSkuEdite dto) {
        PpGoods byId = getById(dto.getGoodsId());
        Assertion.nullThrow(byId, "商品不存在");
        Assertion.emptyThrow(dto.getSkus(), "规格不为空");
        List<PpGoodsAttr> attrs = attrService.list(new LambdaQueryWrapper<PpGoodsAttr>()
                .eq(PpGoodsAttr::getGoodsId, dto.getGoodsId()));
        if (CollectionUtil.isEmpty(attrs)) {
            throw BizExcept.erro("请添加属性");
        }

        Map<String, String[]> attrValsMap = new ConcurrentHashMap<>();
        attrs.forEach(e -> attrValsMap.put(e.getName(), e.getVals()));

        Set<String> skuValues = new ConcurrentHashSet<>();
        BigDecimal price = dto.getSkus().get(0).getPrice();
        for (PpGoodsSkuEdite.Sku sku : dto.getSkus()) {
            if (sku.getPrice().compareTo(price) < 0) {
                price = sku.getPrice();
            }
            if (sku.getAttrInfo().size() != attrs.size()) {
                throw BizExcept.erro("规格和属性不匹配");
            }
            List<String> skuValue = new ArrayList<>();
            for (Map.Entry<String, String> entry : sku.getAttrInfo().entrySet()) {
                String name = entry.getKey();
                String value = entry.getValue();
                skuValue.add(value);
                String[] vals = attrValsMap.get(name);
                if (Objects.isNull(vals) || vals.length == 0 || !ArrayUtil.contains(vals, value)) {
                    throw BizExcept.erro("规格和属性不匹配");
                }
            }
            skuValue.sort(String::compareTo);
            skuValues.add(CollectionUtil.join(skuValue, ","));
        }
        PpGoods editeGoods = new PpGoods();
        editeGoods.setGoodsId(byId.getGoodsId());
        editeGoods.setPrice(price);
        updateById(editeGoods);

        //红色,L ,红色,L
        if (skuValues.size() != dto.getSkus().size()) {
            throw BizExcept.erro("规格值不能重复");
        }

        //需要保存的
        List<PpGoodsSkuEdite.Sku> addlist = dto.getSkus().stream().filter(e -> e.getSkuId() == null).toList();
        List<PpGoodsSku> addSkus = BeanUtil.copyToList(addlist, PpGoodsSku.class);
        addSkus.forEach(e -> e.setGoodsId(dto.getGoodsId()));


        //需要更新的
        List<PpGoodsSkuEdite.Sku> updatelist = dto.getSkus().stream().filter(e -> e.getSkuId() != null).toList();
        List<PpGoodsSku> updateSkus = BeanUtil.copyToList(updatelist, PpGoodsSku.class);
        updateSkus.forEach(e -> e.setGoodsId(dto.getGoodsId()));


        Set<Long> remaindIds = updateSkus.stream().map(PpGoodsSku::getSkuId).collect(Collectors.toSet());

        //删除不存在的
        skuService.remove(new LambdaQueryWrapper<PpGoodsSku>()
                .notIn(!CollectionUtil.isEmpty(remaindIds), PpGoodsSku::getSkuId, remaindIds)
                .eq(PpGoodsSku::getGoodsId, dto.getGoodsId()));

        skuService.saveBatch(addSkus);
        skuService.updateBatchById(updateSkus);
    }

    @Override
    public AdminMiniappGoodsDetailVo getDetail(Long goodsId) {
        PpGoods byId = getById(goodsId);
        Assertion.nullThrow(byId, "商品不存在");

        AdminMiniappGoodsDetailVo vo = BeanUtil.copyProperties(byId, AdminMiniappGoodsDetailVo.class);
        vo.setCoverUrl(ossStore.getUrl(vo.getCover()));
        if (ArrayUtil.isNotEmpty(vo.getSliders())) {
            vo.setSlidersUrl(Arrays.stream(vo.getSliders()).map(e -> ossStore.getUrl(e)).toArray(String[]::new));
        }

        String freeFrom = configService.getConfigByName(Constants.sysFreeFrom);
        if(StrUtil.isNotBlank(freeFrom)){
            vo.setSysFreeFrom(new BigDecimal(freeFrom));
        }

        List<PpGoodsAttr> attrs = attrService.list(
                new LambdaQueryWrapper<PpGoodsAttr>().eq(PpGoodsAttr::getGoodsId, goodsId));
        vo.setAttrs(attrs);
        List<PpGoodsSku> skus = skuService.list(
                new LambdaQueryWrapper<PpGoodsSku>().eq(PpGoodsSku::getGoodsId, goodsId));
        skus.forEach(e -> {
            e.setCoverUrl(ossStore.getUrl(e.getCover()));
            e.setAttrInfoStr(CollUtil.join(e.getAttrInfo().values(),","));
        });
        vo.setSkus(skus);
        return vo;
    }

    @Override
    @Transactional
    public void categorizeUpdate(PpGoodsCategorizeEdite dto) {
        PpGoods byId = getById(dto.getGoodsId());
        Assertion.nullThrow(byId, "商品不存在");

        //1.更新一下商品表中的cat_ids
        PpGoods editeGoods = new PpGoods();
        editeGoods.setGoodsId(dto.getGoodsId());
        editeGoods.setCatIds(dto.getCatIds());
        updateById(editeGoods);

        //2.删除已经不存在的分类  关联表
        List<Long> catIds = ArrayUtil.isEmpty(dto.getCatIds()) ? new ArrayList<Long>() :
                Arrays.stream(dto.getCatIds()).toList();
        goodsCategorizeService.remove(
                new LambdaQueryWrapper<PpGoodsCategorize>()
                        .eq(PpGoodsCategorize::getGoodsId, dto.getGoodsId())
                        .notIn(!CollectionUtil.isEmpty(catIds), PpGoodsCategorize::getCateId, catIds)
        );

        //3.添加需要新增的
        List<PpGoodsCategorize> existCats = goodsCategorizeService.list(new LambdaQueryWrapper<PpGoodsCategorize>()
                .eq(PpGoodsCategorize::getGoodsId, dto.getGoodsId()));

        Set<Long> existCatIds = existCats.stream().map(PpGoodsCategorize::getCateId).collect(Collectors.toSet());
        List<Long> saveIds = catIds.stream().filter(e -> !existCatIds.contains(e)).toList();
        List<PpGoodsCategorize> saveCats = new ArrayList<>();
        for (Long saveId : saveIds) {
            PpGoodsCategorize categorize = new PpGoodsCategorize();
            categorize.setCateId(saveId);
            categorize.setGoodsId(dto.getGoodsId());
            saveCats.add(categorize);
        }
        goodsCategorizeService.saveBatch(saveCats);
    }

    @Override
    public void statusSwitch(PpGoodsStatusSwitch dto) {
        PpGoods byId = getById(dto.getGoodsId());
        Assertion.nullThrow(byId, "商品不存在");
        PpGoods editeGoods = new PpGoods();
        editeGoods.setGoodsId(dto.getGoodsId());
        editeGoods.setStatus(AdminConstants.statusActive.equals(byId.getStatus()) ?
                AdminConstants.statusDisabled : AdminConstants.statusActive);
        updateById(editeGoods);
    }

    @Override
    public List<MiniappGoodsVo> getGoodsByCateId(Long cateId) {
        List<PpGoods> list = baseMapper.getGoodsByCateId(cateId);
        list.forEach(e -> e.setCover(ossStore.getUrl(e.getCover())));
        return BeanUtil.copyToList(list, MiniappGoodsVo.class);
    }

    @Override
    public PageBean<MiniappGoodsVo> search(GoodsSearch dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        Set<String> allows= Set.of("price","sales", "updated_time");
        List<OrderItem> orderItems = dto.getOrderItems().stream().filter(e -> allows.contains(e.getColumn())).toList();
        List<PpGoods> res = baseMapper.search(dto.getKey(), orderItems);
        for (PpGoods good : res) {
            good.setCover(ossStore.getUrl(good.getCover()));
        }

        return PageUtil.load(new PageInfo<>(res), MiniappGoodsVo.class);
    }
}
